﻿namespace FormStateKeeper
{
    using System;
    using System.Collections.Specialized;
    using System.Web;

    /// <summary>
    /// This class encapsulates the form state and provides static methods for storing and retrieving it inside the same request and across requests. 
    /// </summary>
    [Serializable]
    public sealed class FormState
    {
        private static readonly object FormRestoreKey = new object();
        private static readonly IFormStateStorageProvider _storageProvider = new HttpCacheFormStateStorage();
        private readonly string _id;
        private readonly string _path;
        private readonly NameValueCollection _form;

        /// <summary>
        /// Initializes a new instance of the <see cref="FormState"/> class.
        /// </summary>
        /// <param name="id">The unique id of this form state.</param>
        /// <param name="path">The path of the original form post request.</param>
        /// <param name="form">The form to save.</param>
        internal FormState(string id, string path, NameValueCollection form)
        {
            _id = id;
            _path = path;
            _form = form;
        }

        /// <summary>
        /// Gets the unique id of this form state.
        /// </summary>
        public string StateId
        {
            get { return _id; }
        }

        /// <summary>
        /// Gets the path of the original form post request.
        /// </summary>
        public string Path
        {
            get { return _path; }
        }

        /// <summary>
        /// Gets the saved form.
        /// </summary>
        public NameValueCollection Form
        {
            get { return _form; }
        }

        /// <summary>
        /// Gets the FormState instance stored in the HttpContext.Items collection of this request.
        /// </summary>
        /// <param name="context">The current http context.</param>
        /// <returns>The form state.</returns>
        public static FormState GetCurrent(HttpContextBase context)
        {
            if (context == null)
                return null;
            return context.Items[FormRestoreKey] as FormState;
        }

        /// <summary>
        /// Puts the supplied FormState into the HttpContext.Items collection. This way it can be accessed from the FormSaverHttpModule.
        /// </summary>
        /// <param name="context">The current http context.</param>
        /// <param name="state">The form state instance.</param>
        public static void SetCurrent(HttpContextBase context, FormState state)
        {
            if (context != null)
                context.Items[FormRestoreKey] = state;
        }

        /// <summary>
        /// Creates a new FormState instance from the form post of the request of the supplied http context.
        /// Persists this instance using the 
        /// </summary>
        /// <param name="context">HttpContext containing the request / form post</param>
        /// <returns>The created form state.</returns>
        public static FormState Create(HttpContextBase context)
        {
            FormState result = null;
            if (context != null && context.Request.Form != null)
            {
                string id = Guid.NewGuid().ToString();
                result = new FormState(id, context.Request.Path, context.Request.Form);
                _storageProvider.Store(result);
            }

            return result;
        }

        /// <summary>
        /// Creates a new instance by retreiving it from the Form state storage provider, using the specified unique id.
        /// </summary>
        /// <param name="id">The unique id of the saved form state.</param>
        /// <returns>The loaded form state.</returns>
        public static FormState Load(string id)
        {
            FormState result = null;
            if (!string.IsNullOrEmpty(id))
            {
                result = _storageProvider.Retrieve(id);
            }

            return result;
        }

        /// <summary>
        /// Deletes this form state from the form state storage provider.
        /// </summary>
        public void Delete()
        {
            _storageProvider.Delete(this._id);
        }
    }
}
